<template>
	<view>
		<view class="grid">
			<view class="grid-item" v-for="(item, index) in imgList" :key="index">
				<image
					class="image"
					v-if="item.url || item.path"
					:src="item.url || staticUrl + item.path"
					mode="aspectFit"
					:data-url="item.url || staticUrl + item.path"
					@tap="viewImage"
				></image>
				<view class="progress-box" v-if="item.progress">
					<progress :percent="item.progress" :activeColor="item.error ? '#dd524d' : '#4cd964'" stroke-width="3" />
				</view>
				<view class="image-delete" v-if="!disabled" @tap.stop="delImg" :data-index="index">
					<text class="uwo uwo-close-circle-fill"></text>
				</view>
				<view class="upload-error" v-if="item.error">
					<text>上传失败</text>
				</view>
			</view>
			<view class="grid-item" @tap="chooseImage" v-if="imgList.length < maxCount && !disabled">
				<text class="uwo uwo-cameraadd"></text>
			</view>
		</view>

		<!-- 设置canvas用于添加水印 -->
		<canvas
			id="canvasWaterMark"
			canvas-id="canvasWaterMark"
			style="position: fixed; left: -5000px; top: -5000px"
			:style="{
				width: canvasWidth,
				height: canvasHeight
			}"
		></canvas>
	</view>
</template>

<script setup>
import { nextTick, ref, watch } from 'vue';

import ImageTool from './js/ImageTool.js';

const props = defineProps({
	// 显示已上传的文件列表
	modelValue: {
		type: Array,
		default() {
			return [];
		}
	},
	// 文件访问跟地址
	staticUrl: {
		type: String,
		default() {
			return '';
		}
	},
	// 文件上传地址
	uploadUrl: {
		type: String,
		default() {
			return '';
		}
	},
	// 最大上传数量
	maxCount: {
		type: Number,
		default: 5
	},
	// 最大限制大小，单位kb ，设置为-1 则不限制
	maxSize: {
		type: Number,
		default: 1024
	},
	// 是否禁用
	disabled: {
		type: Boolean,
		default: false
	},
	// 请求头
	headers: {
		validator: function (value) {
			if (value) {
				return typeof value === 'object' || typeof value === 'function';
			} else {
				return true;
			}
		},
		default: function () {
			return {};
		}
	},
	// 请求参数
	params: {
		validator: function (value) {
			if (value) {
				return typeof value === 'object' || typeof value === 'function';
			} else {
				return true;
			}
		},
		default: function () {
			return {};
		}
	},
	//文件选择前调用
	beforeChoose: {
		validator: function (value) {
			if (value) {
				return typeof value === 'function';
			} else {
				return true;
			}
		},
		default: false
	},
	//水印内容
	watermark: {
		type: Function
	},
	// 请求参数
	handleChooseImage: {
		validator: function (value) {
			if (value) {
				return typeof value === 'function';
			} else {
				return true;
			}
		},
		default: false
	}
});

const imgList = ref([]);
const canvasWidth = ref('750px');
const canvasHeight = ref('750px');

watch(
	() => props.modelValue,
	(val) => {
		if (val) {
			imgList.value = [...val];
		}
	},
	{
		immediate: true
	}
);
const emits = defineEmits(['update:modelValue', 'change']);
/**
 * 选择图片
 */
const chooseImage = async () => {
	// 为避免脏数据，上传过程中禁止新增
	if (imgList.value.filter((i) => i.id !== undefined).length > 0) {
		uni.showToast({
			mask: true,
			icon: 'none',
			title: '请等待上一个传输完成...'
		});
		return;
	}
	if (props.beforeChoose) {
		const result = await props.beforeChoose();
		if (!result) {
			return;
		}
	}
	let file = {
		url: '',
		size: 0,
		name: '',
		id: Date.now(),
		progress: 0,
		error: false
	};

	const imageTool = new ImageTool({
		watermark: (props.watermark && props.watermark()) || [],
		maxSize: props.maxSize
	});

	imageTool
		.choose({
			chooseOk: (res) => {
				file.url = res.path;
				file.size = res.size;
				file.name = res.name;
				imgList.value.push(file);
			},
			addWaterBefore: (res) => {
				canvasWidth.value = res.width + 'px';
				canvasHeight.value = res.height + 'px';
			}
		})
		.then((res) => {
			if (typeof res === 'string') {
				file.url = res;
			} else {
				file.url = '';
				file.files = res;
			}
			fileUpload(file);
		})
		.catch(() => {
			uploadError(file);
		});
};
/**
 * 上传图片
 */
const fileUpload = (file) => {
	uni.showLoading({
		title: '正在上传...'
	});
	let param = {};
	if (props.params) {
		if (typeof props.params === 'function') {
			param = props.params();
		} else if (typeof props.params === 'object') {
			param = props.params;
		}
	}
	let header = {};
	if (props.headers) {
		if (typeof props.headers === 'function') {
			header = props.headers();
		} else if (typeof props.headers === 'object') {
			header = props.headers;
		}
	}
	const task = uni.uploadFile({
		url: props.uploadUrl,
		filePath: file.url,
		name: 'file',
		file: file.files,
		formData: param,
		header: header,
		success: (result) => {
			if (result.statusCode != 200) {
				/* 失败 */
				uploadError(file);
				return;
			}
			let res = result.data;
			if (res instanceof String || typeof res === 'string') {
				res = JSON.parse(res);
			}
			if (res.code != 1) {
				uploadError(file);
				return;
			}
			const data = res.data;
			if (!(data.url || data.path)) {
				uploadError(file);
				return;
			}
			imgList.value[imgList.value.findIndex((v) => v.id === file.id)] = data;
			uni.hideLoading();
			uni.showToast({
				icon: 'success',
				title: '上传成功'
			});
			handleChange();
		},
		fail: () => {
			uploadError(file);
		}
	});
	// 上传进度监听
	task.onProgressUpdate((res) => {
		if (res.progress > 0) {
			imgList.value[imgList.value.findIndex((v) => v.id === file.id)].progress = res.progress;
		}
	});
};
/**
 * 触发事件
 */
const handleChange = () => {
	emits('update:modelValue', imgList.value);
	emits('change', imgList.value);
};
/**
 * 文件上传失败处理
 */
const uploadError = (file) => {
	uni.hideLoading();
	imgList.value[imgList.value.findIndex((v) => v.id === file.id)].error = true;
	uni.showToast({
		icon: 'error',
		title: '上传失败'
	});
	setTimeout(() => {
		imgList.value = imgList.value.filter((v) => v.id !== file.id);
	}, 1500);
};

/* 预览 */
const viewImage = (e) => {
	const urls = [];
	imgList.value.forEach((v) => {
		urls.push(v.url || props.staticUrl + v.path);
	});
	uni.previewImage({
		urls: urls,
		current: e.currentTarget.dataset.url
	});
};
/* 删除 */
const delImg = (e) => {
	const index = e.currentTarget.dataset.index;
	uni.showModal({
		title: '提示',
		content: '您确定要删除此项吗？',
		success: (res) => {
			if (res.confirm) {
				imgList.value.splice(index, 1);
				handleChange();
			}
		}
	});
};
</script>

<style scoped lang="scss">
@import 'css/iconfont.css';

.grid {
	display: flex;
	flex-wrap: wrap;
	overflow: hidden;

	.grid-item {
		padding-bottom: calc((100% - 60rpx) / 4);
		height: 0;
		width: calc((100% - 60rpx) / 4);
		margin-right: 20rpx;
		margin-top: 20rpx;
		border-radius: 6rpx;
		overflow: hidden;
		position: relative;
		background-color: #f0f0f0;

		&:nth-child(4n) {
			margin-right: 0;
		}

		.image-delete {
			position: absolute;
			right: 2rpx;
			top: 2rpx;

			.uwo {
				color: #e43d33;
				font-size: 20px;
			}
		}

		.progress-box {
			position: absolute;
			bottom: 0;
			left: 0;
			width: 100%;
		}

		.upload-error {
			position: absolute;
			width: 100%;
			font-size: 14px;
			color: #e43d33;
			text-align: center;
			background-color: rgba(0, 0, 0, 0.5);
		}

		.image {
			width: 100%;
			height: 100%;
			position: absolute;
			top: 0;
			left: 0;
		}

		.uwo-cameraadd {
			font-size: 80rpx;
			color: #8f939c;
			position: absolute;
			margin: auto;
			top: 0;
			bottom: 0;
			left: 0;
			right: 0;
			display: flex;
			justify-content: center;
			align-items: center;
			flex-direction: column;
			border-radius: 6rpx;
			border: 1rpx solid #ededed;
		}
	}
}
</style>